<?php

namespace Ktnw\VodSupport\Controllers;

use Exception;
use Illuminate\Routing\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Ktnw\VodSupport\Utils\AliVod;
use Ktnw\VodSupport\Utils\UploadVideoQuery;
use Ktnw\VodSupport\Validators\VodValidator;
use Prettus\Validator\Exceptions\ValidatorException;
use ReflectionClass;
use ReflectionException;

/**
 * @group video controller api
 * 阿里云视频点播相关接口
 *
 */
class VodController extends Controller
{

    /**
     * 操作成功标志
     */
    private const SUCCESS = 1;

    /**
     * 操作失败标志
     */
    private const FAIL = -1;

    /**
     * 响应代码的key
     */
    private const CODE = "code";

    /**
     * 响应提示信息的key
     */
    private const MESSAGE = "message";

    /**
     * 响应代码的key
     */
    private const DATA = "data";

    private $vodValidator;

    public function __construct(VodValidator $vodValidator)
    {
        $this->vodValidator = $vodValidator;
    }


    /**
     * 获取播放凭证
     *
     * @param Request $req
     * @return JsonResponse
     * @throws ValidatorException
     */
    public function getPlayAuth(Request $req): JsonResponse
    {
        $this->vodValidator->with($req->all())->passesOrFail("getPlayAuth");
        $previewTime = $req->input("previewTime", 0);
        $previewTime = empty($previewTime) ? 0 : $previewTime;
        $playAuth    = AliVod::getPlayAuth($req->input('videoId'), $previewTime);
        return $this->success($playAuth);
    }


    /**
     * 获取视频上传地址和凭证
     *
     * @param Request $req
     * @param UploadVideoQuery $query
     * @return JsonResponse
     * @throws ValidatorException
     * @throws Exception
     */
    public function getUploadVideoAuth(Request $req, UploadVideoQuery $query): JsonResponse
    {
        $params             = $req->all();
        $params["fileName"] = empty($params["fileName"]) ? "" : strtolower($params["fileName"]);
        $this->vodValidator->with($params)->passesOrFail("getUploadVideoAuth");
        // 封装前端参数
        $this->getParameters($query);
        if (!in_array($query->getCateId(), $this->getCateIds())) {
            throw new Exception("视频分类ID不存在");
        }
        // 设置视频上传的目录 TODO
        $query->setCateId("");
        // 设置视频上传后的转码模板 TODO
        $query->setTemplateGroupId("");
        $auth = AliVod::getUploadVideoAuth($query);
        if (empty($auth)) {
            throw new Exception("参数错误");
        }
        $auth["VodAccountId"] = AliVod::getVodAccountId();
        return $this->success($auth);
    }

    /**
     * 获取视频上传的目录列表
     * @return array
     */
    private function getCateIds(): array
    {
        return [
            "1000309083", // 目录: 线上研学-学生上传视频
        ];
    }

    /**
     * 刷新视频上传凭证
     *
     * @authenticated
     * @bodyParam videoId string required 视频id.
     *
     * @param Request $req
     * @return string
     * @throws ValidatorException
     */
    public function refreshUploadVideo(Request $req): string
    {
        $this->vodValidator->with($req->all())->passesOrFail("refreshUploadVideo");
        $auth = AliVod::refreshUploadVideo($req->input("videoId"));
        return $this->success($auth);
    }

    /**
     * 删除视频
     *
     * @authenticated
     * @bodyParam requestId string required 上传视频的RequestId.
     * @bodyParam videoId string required 视频id.
     *
     * @param Request $req
     * @return string
     * @throws ValidatorException
     */
    public function deleteUploadVideo(Request $req): string
    {
        $this->vodValidator->with($req->all())->passesOrFail("deleteUploadVideo");
        $video = AliVod::getVideoInfo($req->input("videoId"));
        if (empty($video)) {
            return $this->fail("视频不存在");
        }
        if ($video["RequestId"] != $req->input("requestId")) {
            return $this->fail("无权访问");
        }
        $auth = AliVod::deleteVideo($req->input("videoId"));
        return $this->success($auth);
    }

    /**
     * 利用反射封装前端传递参数
     * @param object $class
     * @return mixed
     */
    private function getParameters(&$class)
    {
        try {
            $refClass   = new ReflectionClass($class);
            $properties = $refClass->getProperties();
            // 反射获取到类的属性信息
            foreach ($properties as $property) {
                $prop = $property->getName();
                $val  = request($prop, '');
                if (isset($val) && $val === "") {
                    continue;
                }
                // 替换特殊字符
                if (is_string($val)) {
                    $val = $this->strReplaceHtml($val);
                }
                if (!$property->isPublic()) {
                    // 给非公有属性设置访问权限
                    $property->setAccessible(true);
                }
                $property->setValue($class, $val);
            }
        } catch (ReflectionException $e) {
            Log::error($e->getMessage());
        }
    }

    /**
     * 替换字符串中的特殊字符
     * \r \n \r\n 替换为 <br>
     * &转成&amp;
     * "转成&quot;
     * ' 转成&#039;
     * <转成&lt;
     * >转成&gt;
     * @param $value
     * @return string|string[]|null
     */
    static function strReplaceHtml($value)
    {
        if ($value === '0' || $value === 0) {
            return '0';
        }

        if (empty($value)) {
            return '';
        }
        $value = preg_replace('/\r\n|\r|\n/', '<br>', $value);
        $value = htmlspecialchars(nl2br($value));
        return preg_replace("/'/", '&#039;', $value);
    }


    /**
     * 操作成功响应
     * @param mixed $data
     * @param string $message 提示信息
     * @return JsonResponse
     */
    private function success($data = [], string $message = ''): JsonResponse
    {
        return $this->out([self::CODE => self::SUCCESS, self::MESSAGE => $message, self::DATA => $data]);
    }

    /**
     * 操作失败响应
     * @param string $message
     * @return JsonResponse
     */
    private function fail(string $message = ''): JsonResponse
    {
        return $this->out([self::CODE => self::FAIL, self::MESSAGE => $message]);
    }

    /**
     * 响应
     * @param $data
     * @return mixed
     */
    private function out($data): JsonResponse
    {
        return response()->json($data)
            ->header('Content-Type', 'text/json')
            ->setEncodingOptions(JSON_UNESCAPED_UNICODE);
    }

}
